/*
 * 代号：凤凰
 * http://www.jphenix.org
 * 2014-06-13
 * V4.0
 */
package com.jphenix.webserver.instancea;

import com.jphenix.driver.json.Json;
import com.jphenix.driver.nodehandler.FNodeHandler;
import com.jphenix.driver.propertie.FConfProp;
import com.jphenix.driver.propertie.instanceb.XmlConfProp;
import com.jphenix.share.lang.SBoolean;
import com.jphenix.share.lang.SInteger;
import com.jphenix.share.lang.SString;
import com.jphenix.share.util.DebugUtil;
import com.jphenix.share.util.SFilesUtil;
import com.jphenix.standard.docs.ClassInfo;
import com.jphenix.standard.exceptions.EmptyException;
import com.jphenix.standard.propertie.IConfigSetter;
import com.jphenix.standard.viewhandler.INodeHandler;
import com.jphenix.standard.viewhandler.IViewHandler;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 服务参数处理类
 * 
 * com.jphenix.webserver.instancea.ServeParameter
 * 
 * 2018-11-08 在加载配置文件前，先判断了文件是否存在
 * 2019-09-17 整理了代码格式
 * 2020-08-06 去掉了配置文件接口，改为直接使用实体类
 * 2021-09-12 增加了配置文件格式说明
 * 2022-09-04 重构了内置Servlet容器，不依赖外部ServletApi包
 * 2022-10-20 重新适配了配置文件类
 * 2023-10-10 修改了命令行方式启动web服务，端口参数无效的问题
 * 2024-07-09 增加了获取会话配置信息和Cookie配置信息
 * 2024-07-12 增加了同时支持http和https两种模式
 * 2024-07-23 新增连接超时参数
 * 2024-08-11 新增如果外部没有web.xml，则从框架jar包中获取（单jar包模式）
 * 
 * 启动参数分三种情况（中括号代表可选参数）：
 * 
 * 普通监听：
 * 1 [监听端口] [虚拟路径] [json 格式的扩展参数]
 * 
 * SSL监听：
 * 2 [监听端口] [虚拟路径] [json 格式的扩展参数]
 * 
 * 同时支持普通监听和SSL监听：
 * 
 * 3 [普通监听端口] [虚拟路径] [json 格式的扩展参数]
 * 
 * 
 * json 格式的扩展参数：
 * 
 *   SessionTimeOut : 会话超时时间（分）
 *   ConnTimeOut    : web服务连接超时时间（秒）
 * 
 * 
 * 
 * 
 * 在这种模式下，SSL监听端口是普通监听端口值+1
 * 
 * 配置文件路径
 * <配置文件路径>
 * 
 * -------------------------
 * 
 * phserver.xml 内容：
 * 
 * <?xml version="1.0" encoding='UTF-8'?>
 * <root>
 *   <!-- Web Server For Phenix v3.0 -->
 *   <enabled-ssl></enabled-ssl>          <!-- 是否启用SSL -->
 *   <only-ssl></only-ssl>                <!-- 是否只允许SSL -->
 *   <keystore-type></keystore-type>      <!-- 证书库类型 JKS PKCS12 -->
 *   <sslport></sslport>                  <!-- SSL监听端口 -->
 *   <keystorePass>chenxin</keystorePass> <!-- 证书密码，如果需要的话 -->
 *   <port>80</port>                      <!-- 常规监听端口 -->
 *   <context-path>/</context-path>       <!-- 虚拟路径 -->
 *   <backlog>0</backlog>                 <!-- Socket Backlog -->
 *   <session-timeout></session-timeout>  <!-- 会话超时时间(分钟) -->
 *   <notnohup>yes</notnohup>             <!-- 是否在控制窗口控制网站 yes(可以在控制台终止服务) no不支持 -->
 *   <out-serv-log>false</out-serv-log>   <!-- 是否输入普通服务器日志 -->
 *   <keep-alive>true</keep-alive>        <!-- 浏览器与服务器是否进行持久连接 -->
 *   <WebBasePath>../..</WebBasePath>     <!-- 网站根路径 -->
 *   <max-execute_thread_count>50</max-execute_thread_count>     <!-- Servlet最大处理线程数 -->
 *   <after-start-execute-command></after-start-execute-command> <!-- 网站启动后执行命令行 -->
 * </root>
 * 
 * 
 * @author 刘虻
 * 2007-9-29下午03:57:14
 */
@ClassInfo({"2024-08-11 23:57","服务参数处理类"})
public class ServeParameter implements IConfigSetter {

    private String webBasePath     = null; //网站根路径
    private String servletBasePath = null; //服务程序根路径
                        
    private List<String>           mimeKeyList              = null;            // mime主键序列
    private List<String>           welcomeFileList          = null;            // 默认访问文件序列
    private Map<String,String>     sessionConfigMap         = new HashMap<>(); // 会话配置信息
    private Map<String,String>     cookieConfigMap          = new HashMap<>(); // cookie配置信息
    
    private XmlConfProp            confProp                 = null;            // 配置文件处理类
    private Map<String,String>     mimeMap                  = null;            // mime容器
    private Map<String,String>     confDataMap              = new HashMap<>(); // 需要设置到配置文件中的参数容器
    private String                 contextPath              = null;            // 虚拟路径　（目前该服务器只能有一个虚拟路径）
    private int                    contextPathLength        = -1;              // 虚拟路径长度
    private int                    sessionTimeOut           = 0;               // 会话超时时间
    private String                 configFilePath           = null;            // 配置文件路径
    private boolean                secure                   = false;           // 是否启用安全会话
    private boolean                httpOnly                 = true;            // 会话主键是否不落地 默认为true
    private INodeHandler           webXmlNode               = null;            // web.xml对象
    private Json                   extPara                  = new Json();      // 扩展启动参数对象
    
    /**
     * 文本配置文件
     */
    public  final static String CONFIG_TEXT_FILE_NAME = "phserver.xml";
    private final        String WEB_BASE_PATH         = "WebBasePath";     // 网站根路径
    private final        String ARG_CONTEXT_PATH      = "context-path";    // 虚拟路径
    private final        String ARG_SESSION_TIMEOUT   = "session-timeout"; // 会话超时时间(秒)
    private final        int    DEF_SESSION_TIMEOUT   = 1800;              // 默认会话超时时间(默认30分钟)
    
    // 默认证书库
    public static String DEFAULT_KEYSTORE = "30820aa602010330820a5006092a864886f70d010701a0820a4104820a3d30820a39308205b006092a864886f70d010701a08205a10482059d3082059930820595060b2a864886f70d010c0a0102a08205403082053c306606092a864886f70d01050d3059303806092a864886f70d01050c302b041459bac61b28f3631b11cfb81e0f51730a0db5ca4802022710020120300c06082a864886f70d02090500301d060960864801650304012a04106580814ef3b46e3c1f222e577e9dba63048204d09c15b33cd888925c90c544c1703a8870110d005904ca803152516147f80ccf8864aad5b25eddf9a160b47e5a5f0ba0953e93af1a63e2c0bf36d1b61bc7d5a56c24f89d302fb8da3d500d229ca7553c47e9b90045eaaea5dd9395848d87bed7f1061a14f89cfeb381600c3decf15a1b0c45d9a6631b98f9b381f540b30d22eb5496415cf3f07481a4c83ce335685fda558dd72b5e6dc02a3028627dba52f4705a88d0f1c6a1123b8cbef45342f8973e71667d5e8ce18114d0b469d0b0eee275f7b94f5003a04484ea8f289c60fb76710ef8eddd737b1af4302a8db530f44a57444e4471ddcd8a7c9eccd84ff72cc8d975ef94f9747ba5afde3fd529e7a5d4f9c1bd573a5217512cefecd848af05191cb0b66685127604fba4f48ab8a0b62f61977027ea9f0a44ad03ee599a811ffdf50458c6ed3643c93a246455809a28fd835040ba32f3343d6d4034a2a491adbd3831fcdcf871bc56dc83964dae4437ad19bc4c1dbf85ccf227c2043357fa65293152b26872cf0b3c627fe02493f69a470e7a256d02507c35b222ec62fac34b4b1592827df0fce37bf895da5ff3f81c3f5ac0c8b58e10d50e7bf43956c16b6e56ad22ef228ee845512f9b21a32e1324e588b4391454f4140492a0240b4757b2e056636e4d56e5c1b26bce9800ceb08ed605320649ad9148dcc009df711aaf251078e4c099d24ff467f72fcfbf4be7cf1200d2b1fc2960270d1eca3de722ecdfb10c5d0bffbc87fbdb7b7df87ae78134a1586a5820a6e4db4c8c54cf8aa6cd1bdd92a8690cda27b6fbe210b5ec09daba44a290fef2675fc4afc2a9b0855cc944649f74ebf6fb441ddde41e47619be3ff9ce313e8b66cd4f10b278e1d1a2b1049206b4f498a453f13c3d9d4b0dc04c1b0fad0c63aabc2bca7fbba23ed974d426f8f71ca93fa01efc9953eeddfd10974c26af96cc64ebf6d97b21f92d58c3aad8cfe7d1883bbe0abf29f97d6e938016990a31b50de6edf83d4713e67d0b1a0a56e5a57025101088a9dd209c097948fc6763c7ba57c400cc7f2afee6cfc7731096c99ab1a25a510f91919b4d7f359de27f1c184e02d32df7be5af86f2135adc354d4c1fb89d23fc480c79513e08219466541d69a264ee5717019e7a6f5d777a118ccb86589252846399e5a8d09da285b004a1f2eedaced9a6899a6ff601f4f7c82caf27be7d24ff797379cd1c4122fa39217d79a0290a320bc8260d0af13fc9192317ac84be64575ba5aebad16d4f4079fafee072cf8b159c4aa0234c3045c15f1e9461cbd8678a760c72859738f6b1fefafef1c50487e256e5444ce9b2cd0d766def6bdddb85fbb194dd6b9caf97de801f554a2a4a0e2e37eb4267fd28fad00761390d6cf461ac5ea8e757f9bfaaccd3ba9dc83d01184631da03a8936c84ffe9f15c22a03a75136152513c6c1775333d3868685054d3f88163369e1a42f2eb5a5f0cc2afe2f1c049c9e9a672668912a668aa884098a63e62a3213ed191b5b503fb8a2505b38e1e6bfc8342772451bac32b0323aca35b3315290c1f6fc517514b217c6a2c1efa08d38d247fe48170b37cc24d67c41212713921d5475e2f62f5c9af485ea866c3f766eda4644cc519fea77618174152e6ca4a8b6d5eb663e087328a95586127e6ec6d5806c09c3679fb4aa3ff82fba982896a835ea63a0cbb991f07c7fa6f33dc4076cd933a274945496722cef0e03886b168b1295ade0a76a00f4d7981013142301d06092a864886f70d01091431101e0e006a007000680065006e00690078302106092a864886f70d0109153114041254696d6520313730323839383334393431393082048106092a864886f70d010706a08204723082046e0201003082046706092a864886f70d010701306606092a864886f70d01050d3059303806092a864886f70d01050c302b04140206fee4e8b3a62339ab0a3c889cb2a2b6e1f5d202022710020120300c06082a864886f70d02090500301d060960864801650304012a0410ea34e05be881dec13f6a642cadc8c403808203f09587c6569ea5a2f14da288734bd0c8c46f801ba80a107a73870445c579d89f1d6a4d7c531dd1c127ab7b18d0c195ea49573de54dfe7642a65ca5a6b924a42fd4a7d39ee021b9dbd1b440ebc0403f6974f6ceb15ae187e02e19599282c5931277f54dce8aa71deb865c581417bd790ecd35ca07a73c0d6cd68015a8c7d208fc8bd4b29fda6d2fe39f4a65beb89d2b07125edd99cceaaaa29060ed4b20ac0941bebb45a28652d894edf757ff75a60cd5927897a8a6d58aa935cb6f37976c92660ee89bc8dd23f893d0c740389149c9809691b0c46952006b579b48c611c2ebc5b80e235888c3df0403785ceb0f934260e8aaa380f55a8b38ad0392f2ee2c10f4351cc3fcf9923a1dd84fdc1d4bd6721be4e9fc45099b97714afd7aa527f177a53a34a88a70cd03e2605f4365d9f3555c4577cc6f9c009241d83e65b41ad63ecb063471a8d356fdfa8177447aac18a410c22706fe136d8839542cab87c9b91ab7e38a3b0c8a1421a25ea970891482193881372c0023032aa014c915b5532d0c25208aa18dae89c3adda58d3e2f224b66e0f024f591ebee6dd2a095b5c7a2cfc16698e8e531ebe8c72c69930aea7f262faf869520d3d931412b39d3cbb72c3d55a56e967a4135c3836452ce32623eb53f3be7d44674445614c068b95bf98308f0bc0c7e2eeea6e80dc17121081848b8967f78482cf47e33dfdd92cea709aaf80359b8f454836ea2f219fdc5333e4146b5c4d4f0ed5a5cf3c5958077b1065c244bbdacc8d736b282f59ca8391fb889da0cf5ad5fc42747f84d9e695bd524733f4f1004da2e9b216a4c0e098ec93cf2d27350cf6a913d70b31a2729f03e0e947ee22bf3acb379d43e629ad95501b4f17d49133152028f93296a09df07a518e697eaadf3ac6b7063163f43622e64d4e6aaf7420a8b549b203d3bb4074c9c060b0368e1d6ff8d584eaef804880f821f42a83f7773a19c147f9ebe9f7b9511eba8ffa955b62b558186103282b935db5a80e6bbc2509d7d5df8a19077449d68d3fb326299a7e46fe51ab9c2583841d66ab718153e4f31aa75909d7b03d9959e247ea5e23feee273e2f366cadf76a7b08ed4225193e0920f2d63728764d47c68fb0ec7530d4acc70e035446e22066ec617250a1a8f80b2e4c43e7cf69b756433700ceb7a15ad09b17f61182079ed49d289f5a7d3c8e354dc144c77400be1cd1ec51e5d6930205c5d010c12342b8712e7285060f0cb96489778d747dbb8618e8613560f1c3eda70cc0e064188f7d1a2bed2dbe556ed63a29f28a5981eba6fd2108687cc6ea712e0870a8773c68a840b5f1d8198eca4959983b98981ccac7d3f26f460dcd17cf4d657073d6c159fb00add8fa02053c3d7c0b2b048d9d1f6d5026792e890ed252e7132b85a93b0361f4375d1861e8cb66304d3031300d060960864801650304020105000420c3ec9fd0c54a22b38cca0d1716c33e784013d5588e5aa9934959fa2d526f48c40414e5b2a3e42cc60013ec07346701e207ef813954ed02022710";
    
    // 默认证书密码
    public static String DEFAULT_KEY_PASSWD = "chenxinsoft";
    
    /**
     * 构造函数
     * 2007-9-29下午03:57:14
     */
    public ServeParameter() {
        super();
    }
    
    
    /**
     * 获取有效的配置文件处理类
     * @author 刘虻
     * 2008-6-28下午02:31:43
     * @return 配置文件处理类
     */
    public XmlConfProp getConfProp() {
        return confProp;
    }
    
    //#region getExtPara() 获取扩展参数Json对象
    /**
     * 获取扩展参数Json对象
     * @return 扩展参数Json对象
     * 2024年7月23日
     * @author MBG
     */
    public Json getExtPara() {
    	return extPara;
    }
    //#endregion
    
    /**
     * 获取虚拟路径
     * @return 虚拟路径
     * 2022年9月3日
     * @author MBG
     */
    public String getContextPath() {
    	if(contextPath==null) {
    		//获取虚拟路径
    		contextPath = getArgumentString(ARG_CONTEXT_PATH);
    		if (contextPath.equals("/")) {
    			contextPath = "";
    		}
    	}
    	return contextPath;
    }
    
	/**
	 * 获取虚拟路径长度
	 * @author 刘虻
	 * 2008-9-8下午03:54:17
	 * @return 虚拟路径长度
	 */
	public int getContextPathLength() {
		if(contextPathLength<0) {
			contextPathLength = getContextPath().length();
		}
		return contextPathLength;
	}

    /**
     * 获取参数容器
     * @author 刘虻
     * 2007-9-30下午03:45:53
     * @return 参数容器
     */
    public Map<String,Object> getArgumentMap() {
        return getConfProp().getParameterValueMap(null);
    }
    
    
    /**
     * 覆盖方法
     * 刘虻
     * 2012-9-13 下午10:05:09
     */
    public String getConfigFilePath() {
        return configFilePath;
    }


    /**
     * 显示帮助信息
     * 2017年1月31日
     * @author MBG
     */
    private void showHelp() {
    	System.out.println("Nobody ever saw this. See the source code Please.");
    }
    
    
    
    /**
     * 整理启动服务参数
     * 
     * 当第一个参数为 1 时，为直传参数模式
     * 在该模式下，第二个参数为监听端口
     * 第三个传入参数为虚拟路径
     * 直传参数模式只支持者两个参数
     * 
     * @author 刘虻
     * 2006-9-15下午12:21:24
     * @param args 导入参数
     * @return 整理后的参数包容器
     * @throws Exception 整理参数时发生异常
     */
    public void initProp(String[] args) throws Exception  {
        confProp = FConfProp.newInstance(); //构建配置文件处理类
        //获取当前包所在的文件夹
        String localPath = PathUtil.getThisPath(null);
        //构建配置文件对象
        File confFile = new File(localPath+CONFIG_TEXT_FILE_NAME);
        if(confFile.exists()) {
        	configFilePath = confFile.getPath();
            //先加载包同级下的基础配置文件
            try {
                System.out.println("Begin Try Load Base Config File:["+localPath+CONFIG_TEXT_FILE_NAME+"]");
                confProp.parsePropertys(configFilePath);
            }catch(Exception e) {
                System.out.println("The Base Config File Not Loaded. Maybe Not Found");
            }
        }
        if(args!=null && args.length==1 && "?".equals(args[0])) {
        	//显示帮助信息
        	showHelp();
        	throw new EmptyException();
        }
        
        // 配置默认信息
        confDataMap.put("keystorePass","chenxinsoft");
        confDataMap.put("encoding","UTF-8");
        confDataMap.put("backlog","0");
    	confDataMap.put("notnohup","yes");
    	confDataMap.put("keep-alive","true");
    	confDataMap.put("WebBasePath","../..");
        
        if(args!=null && args.length>0 && ("1".equals(args[0]) || "3".equals(args[0]))) {
        	/*
        	 * 当第一个参数为 1 时，为直传参数模式
        	 * 在该模式下，第二个参数为监听端口
        	 * 第三个传入参数为虚拟路径
        	 * 直传参数模式只支持者两个参数
        	 */
        	String port = "";
        	if(args.length>1) {
        		port = args[1].trim();
        	}
        	if(port.length()<1) {
        		port = "80";
        	}
        	String contextPath = ""; //设置默认虚拟路径
        	if(args.length>2 && args[2]!=null && !args[2].startsWith("{")) {
        		contextPath = args[2].trim();
        	}
        	if(contextPath.length()<1) {
        		contextPath = "/";
        	}

        	System.out.println("\n==========================================================================\n Load Parameters[Port:"+port+" ContextPath:"+contextPath+"] sessionTimeOut:["+sessionTimeOut+"]min\n==========================================================================");
        	confDataMap.put("port",port);
        	confDataMap.put("context-path",contextPath);
        }
        if(args!=null && args.length>0 && ("2".equals(args[0]) || "3".equals(args[0]))) {
        	/*
        	 * 当第一个参数为 2 时，为直传参数模式（只开放SSL监听）
        	 * 在该模式下，第二个参数为监听端口
        	 * 第三个传入参数为虚拟路径
        	 * 直传参数模式只支持者两个参数
        	 * 第四个参数为会话超时时间
        	 * 
        	 * 
        	 * 如果第一个参数为3，意味着同时启用 http和https，那端口号是 http的端口号+1
        	 */
        	String port = "";
        	if(args.length>1) {
        		port = args[1].trim();
        	}
        	
        	//#region 如果第一个参数值为3 意味着同时启用http和https，那端口号是 http的端口号+1
        	if("3".equals(args[0]) && port.length()>0) {
        		port = String.valueOf(Integer.parseInt(port)+1);
        	}
        	//#endregion
        	
        	if(port.length()<1) {
        		port = "443";
        	}
        	
        	String contextPath = ""; //设置默认虚拟路径
        	if(args.length>2 && args[2]!=null && !args[2].startsWith("{")) {
        		contextPath = args[2].trim();
        	}
        	if(contextPath.length()<1) {
        		contextPath = "/";
        	}

        	System.out.println("\n==========================================================================\n Load Parameters[SSL-Port:"+port+" ContextPath:"+contextPath+"] sessionTimeOut:["+sessionTimeOut+"]min\n==========================================================================");
        	confDataMap.put("sslport",port);
        	confDataMap.put("enabled-ssl","1");
        	confDataMap.put("context-path",contextPath);
        	
        	if(!"3".equals(args[0])) {
        		confDataMap.put("only-ssl","1");
        	}
        	
        	DebugUtil.outPrintMapValue(confDataMap," ");
        }
        
        if(args==null || args.length<1 || !("1".equals(args[0]) || "2".equals(args[0]) || "3".equals(args[0]))){
            //目标配置文件路径
            String configPath = null;
            if (args!=null && args.length>0 && args[0]!=null && args[0].length()>0) {
                configPath = args[0];
            }else {
                //目标配置文件路径
                configPath = PathUtil.fixUpPath(localPath+"../resfiles/phserver.xml");
            }
            //配置文件对象
            File checkFile = new File(configPath); 
            if(checkFile.exists() && checkFile.isFile()) {
            	System.out.println("Begin Try Load Config File:["+configPath+"]");
            	confProp.parsePropertys(configPath); //设置配置文件路径
            }else{
            	System.out.println("\n==============================================================================================================\nThe Config File Not Loaded. Maybe Not Found [WEB-INF/resfiles/phserver.xml] LoadDefault[Port:80 ContextPath:/]\n==============================================================================================================");
            	confDataMap.put("port","80");
            	confDataMap.put("context-path","/");
            	DebugUtil.outPrintMapValue(confDataMap," ");
            }
        }
        
        //#region 设置扩展参数
        if(args.length>2 && args[2]!=null && args[2].startsWith("{")) {
        	extPara.setString(args[2]);
        }else if(args.length>3 && args[3]!=null && args[3].startsWith("{")) {
        	extPara.setString(args[3]);
        }
        //#endregion
        
        //#region 会话超时时间（分）
        String sValue = extPara.value("SessionTimeOut"); 
        if(sValue.length()>0) {
        	confDataMap.put("session-timeout",sValue);
        }
        //#endregion
        
        //获取网站根路径
        webBasePath = SString.valueOf(confProp.getParameter(WEB_BASE_PATH));
        if(webBasePath.length()<1) {
            webBasePath = "/../..";
        }
        webBasePath = SFilesUtil.getAllFilePath(webBasePath,SFilesUtil.getBaseClassPath((Class<?>)null));
        //获取服务类根路径
        servletBasePath = webBasePath+"/WEB-INF/classes";

        //初始化网站
        
        //解析WEB-INF/web.xml
        
        webXmlNode = FNodeHandler.newNodeHandler();
        webXmlNode.setXmlStyle(true);
        
        File cFile; //检测文件是否存在
        
        /*
         * 先在包根路径中查找基本配置文件
         */

        String baseWebFilePath = PathUtil.fixPath(localPath+"/web.xml");
        cFile = new File(baseWebFilePath);
        if(cFile.exists()) {
            //设置基础配置文件路径
        	webXmlNode.setStream(new FileInputStream(new File(baseWebFilePath)),baseWebFilePath);
            fixWelcomeFileList(webXmlNode); // 处理默认访问文件信息
            fixMimeType(webXmlNode);        // 处理类型信息
        }else {
        	try {
        		// 从框架包中获取
        		InputStream is = getClass().getClassLoader().getResourceAsStream("resources/web.xml");
        		if(is!=null) {
        			webXmlNode.setStream(is,baseWebFilePath);
                    fixWelcomeFileList(webXmlNode); // 处理默认访问文件信息
                    fixMimeType(webXmlNode);        // 处理类型信息
        		}
        	}catch(Exception e) {}
        }
        
        /*
         * 再加载指定项目下的配置文件
         */
        //web.xml文件路径
        String xmlFilePath = 
            PathUtil.fixUpPath(servletBasePath+"/../web.xml");
        cFile = new File(xmlFilePath);
        if (cFile.exists()) {
        	webXmlNode = FNodeHandler.newNodeHandler();
        	webXmlNode.setXmlStyle(true);
            //设置基础配置文件路径
        	webXmlNode.setStream(new FileInputStream(new File(xmlFilePath)),xmlFilePath);
            fixWelcomeFileList(webXmlNode);//处理默认访问文件信息
            fixMimeType(webXmlNode); //处理类型信息
            fixSessionCookieConfig(webXmlNode); // 处理会话和Cookie配置信息
            
            String val = getCookieConfig("secure");
            if(val!=null && val.length()>0) {
            	secure = SBoolean.valueOf(val);
            }
            val = getCookieConfig("http-only");
            if(val!=null && val.length()>0) {
            	httpOnly = SBoolean.valueOf(val);
            }
        }
        
		//获取会话超时时间
		sessionTimeOut = getArgumentInt(ARG_SESSION_TIMEOUT);
		if (sessionTimeOut<1) {
			sessionTimeOut = DEF_SESSION_TIMEOUT;
		}
		// 如果web.xml中存在值，优先取该值
		String webSessionTimeOut = getSessionConfig(ARG_SESSION_TIMEOUT);
		if(webSessionTimeOut!=null && webSessionTimeOut.length()>0){
			sessionTimeOut = SInteger.valueOf(webSessionTimeOut);
		}
    }
    
    /**
     * 是否只允许https访问
     * @return 是否只允许https访问
     * 2024年7月9日
     * @author MBG
     */
    public boolean isSecure() {
    	return secure;
    }
    
    /**
     * 会话主键是否不落地
     * @return 会话主键是否不落地
     * 2024年7月9日
     * @author MBG
     */
    public boolean isHttpOnly() {
    	return httpOnly;
    }

    /**
     * 覆盖方法
     * @author 刘虻
     * 2007-9-30下午03:48:38
     */
    public String getArgumentString(String key) {
    	return SString.valueOf(getPropertyMap().get(key));
    }


    /**
     * 覆盖方法
     * @author 刘虻
     * 2007-9-30下午04:00:00
     */
    public boolean getArgumentBoolean(String key) {
        return SBoolean.valueOf(getArgumentString(key));
    }


    /**
     * 覆盖方法
     * @author 刘虻
     * 2007-9-30下午04:02:18
     */
    public int getArgumentInt(String key) {
        return SInteger.valueOf(getArgumentString(key));
    }


    /**
     * 覆盖方法
     * @author 刘虻
     * 2008-6-28下午03:27:30
     */
    public String getRealPath(String path) {
        if (path==null) {
            return getWebBasePath();
        }
        if (!path.startsWith("/")) {
            path = "/"+path;
        }
        //getWebBasePath() 本身就是绝对路径
        // return serve.getFilesUtil().getAllFilePath(getWebBasePath()+path);
        return SFilesUtil.getAllFilePath(path,getWebBasePath());
    }

    /**
     * 覆盖方法
     * @author 刘虻
     * 2008-6-28下午03:27:27
     */
    public String getServletBasePath() {
        return servletBasePath;
    }

    /**
     * 覆盖方法
     * @author 刘虻
     * 2008-6-28下午03:27:10
     */
    public String getWebBasePath() {
        return webBasePath;
    }
    
    /**
     * 获取Mime主键序列
     * @author 刘虻
     * 2008-6-28下午07:49:40
     * @return Mime主键序列
     */
    private List<String> getMimeKeyList() {
        if (mimeKeyList==null) {
            getMimeMap();
        }
        return mimeKeyList;
    }
    
    
    /**
     * 处理配置文件中的类型信息
     * @author 刘虻
     * 2009-12-11下午02:55:12
     * @param xml 配置文件对象
     */
    private void fixMimeType(IViewHandler xml) {
        //获取类型映射
        List<IViewHandler> xmls = xml.getChildNodesByNodeName("mime-mapping");
        //获取类型序列
        List<String> mKeyList = getMimeKeyList();
        //获取类型对照容器
        Map<String,String> mMap = getMimeMap();
        String extension; //类型主键
        String mimeType; //类型值
        IViewHandler node; //获取类型主键信息节点
        for(IViewHandler cXml:xmls) {
            extension = null; //类型主键
            mimeType = null; //类型值
            node = cXml.getFirstChildNodeByNodeName("extension");
            if(!node.isEmpty()) {
                extension = node.nt();
            }
            node = cXml.getFirstChildNodeByNodeName("mime-type");
            if(!node.isEmpty()) {
                mimeType = node.nt();
            }
            if(extension==null 
                    || extension.length()<1 
                    || mimeType==null 
                    || mimeType.length()<1) {
                continue;
            }
            extension = "."+extension.toUpperCase();
            mMap.put(extension,mimeType);
            if(!mKeyList.contains(extension)) {
                mKeyList.add(extension);
            }
        }
    
    }
    
    /**
     * 获取有效的类型对照容器
     * @author 刘虻
     * 2009-12-11下午02:47:26
     * @return 有效的类型对照容器
     */
    private Map<String,String> getMimeMap() {
        if (mimeMap==null) {
            mimeKeyList = new ArrayList<String>();
            mimeMap = new HashMap<String,String>();
            
            mimeKeyList.add(".HTML");
            mimeMap.put(".HTML","text/html");
            
            mimeKeyList.add(".HTM");
            mimeMap.put(".HTM","text/html");
            
            mimeKeyList.add(".TXT");
            mimeMap.put(".TXT","text/plain");
            
            mimeKeyList.add(".XML");
            mimeMap.put(".XML","text/xml");
            
            mimeKeyList.add(".CSS");
            mimeMap.put(".CSS","text/css");
            
            mimeKeyList.add(".SGML");
            mimeMap.put(".SGML","text/x-sgml");
            
            mimeKeyList.add(".SGM");
            mimeMap.put(".SGM","text/x-sgml");
            
            mimeKeyList.add(".GIF");
            mimeMap.put(".GIF","image/gif");
            
            mimeKeyList.add(".JPG");
            mimeMap.put(".JPG","image/jpeg");
            
            mimeKeyList.add(".JPEG");
            mimeMap.put(".JPEG","image/jpeg");
            
            mimeKeyList.add(".JPE");
            mimeMap.put(".JPE","image/jpeg");
            
            mimeKeyList.add(".PNG");
            mimeMap.put(".PNG","image/png");
            
            mimeKeyList.add(".BMP");
            mimeMap.put(".BMP","image/bmp");
            
            mimeKeyList.add(".TIF");
            mimeMap.put(".TIF","image/bmp");
            
            mimeKeyList.add(".TIFF");
            mimeMap.put(".TIFF","image/bmp");
            
            mimeKeyList.add(".RGB");
            mimeMap.put(".RGB","image/x-rgb");
            
            mimeKeyList.add(".XPM");
            mimeMap.put(".XPM","image/x-xpixmap");
            
            mimeKeyList.add(".XBM");
            mimeMap.put(".XBM","image/x-xbitmap");
            
            mimeKeyList.add(".SVG");
            mimeMap.put(".SVG","image/svg-xml ");
            
            mimeKeyList.add(".SVGZ");
            mimeMap.put(".SVGZ","image/svg-xml ");
            
            mimeKeyList.add(".AU");
            mimeMap.put(".AU","audio/basic");
            
            mimeKeyList.add(".SND");
            mimeMap.put(".SND","audio/basic");
            
            mimeKeyList.add(".MID");
            mimeMap.put(".MID","audio/mid");
            
            mimeKeyList.add(".MIDI");
            mimeMap.put(".MIDI","audio/mid");
            
            mimeKeyList.add(".RMI");
            mimeMap.put(".RMI","audio/mid");
            
            mimeKeyList.add(".KAR");
            mimeMap.put(".KAR","audio/mid");
            
            mimeKeyList.add(".MPGA");
            mimeMap.put(".MPGA","audio/mpeg");
            
            mimeKeyList.add(".MP2");
            mimeMap.put(".MP2","audio/mpeg");
            
            mimeKeyList.add(".MP3");
            mimeMap.put(".MP3","audio/mpeg");
            
            mimeKeyList.add(".WAV");
            mimeMap.put(".WAV","audio/wav");
            
            mimeKeyList.add(".AIFF");
            mimeMap.put(".WAV","audio/aiff");
            
            mimeKeyList.add(".AIFC");
            mimeMap.put(".AIFC","audio/aiff");
            
            mimeKeyList.add(".AIF");
            mimeMap.put(".AIF","audio/x-aiff");
            
            mimeKeyList.add(".RA");
            mimeMap.put(".RA","audio/x-realaudio");
            
            mimeKeyList.add(".RPM");
            mimeMap.put(".RPM","audio/x-pn-realaudio-plugin");
            
            mimeKeyList.add(".RAM");
            mimeMap.put(".RAM","audio/x-pn-realaudio");
            
            mimeKeyList.add(".SD2");
            mimeMap.put(".SD2","audio/x-sd2");
            
            mimeKeyList.add(".BIN");
            mimeMap.put(".BIN","application/octet-stream");
            
            mimeKeyList.add(".DMS");
            mimeMap.put(".DMS","application/octet-stream");
            
            mimeKeyList.add(".LHA");
            mimeMap.put(".LHA","application/octet-stream");
            
            mimeKeyList.add(".LZH");
            mimeMap.put(".LZH","application/octet-stream");
            
            mimeKeyList.add(".EXE");
            mimeMap.put(".EXE","application/octet-stream");
            
            mimeKeyList.add(".DLL");
            mimeMap.put(".DLL","application/octet-stream");
            
            mimeKeyList.add(".CLASS");
            mimeMap.put(".CLASS","application/octet-stream");
            
            mimeKeyList.add(".HQX");
            mimeMap.put(".HQX","application/mac-binhex40");
            
            mimeKeyList.add(".PS");
            mimeMap.put(".PS","application/postscript");
            
            mimeKeyList.add(".AI");
            mimeMap.put(".AI","application/postscript");
            
            mimeKeyList.add(".EPS");
            mimeMap.put(".EPS","application/postscript");
            
            mimeKeyList.add(".PDF");
            mimeMap.put(".PDF","application/pdf");
            
            mimeKeyList.add(".RTF");
            mimeMap.put(".RTF","application/rtf");
            
            mimeKeyList.add(".DOC");
            mimeMap.put(".DOC","application/msword");
            
            mimeKeyList.add(".PPT");
            mimeMap.put(".PPT","application/powerpoint");
            
            mimeKeyList.add(".FIF");
            mimeMap.put(".FIF","application/fractals");
            
            mimeKeyList.add(".P7C");
            mimeMap.put(".P7C","application/pkcs7-mime");
            
            mimeKeyList.add(".JS");
            mimeMap.put(".JS","application/x-javascript");
            
            mimeKeyList.add(".Z");
            mimeMap.put(".Z","application/x-compress");
            
            mimeKeyList.add(".GZ");
            mimeMap.put(".GZ","application/x-gzip");
            
            mimeKeyList.add(".TAR");
            mimeMap.put(".TAR","application/x-tar");
            
            mimeKeyList.add(".TGZ");
            mimeMap.put(".TGZ","application/x-compressed");
            
            mimeKeyList.add(".ZIP");
            mimeMap.put(".ZIP","application/x-zip-compressed");
            
            mimeKeyList.add(".DIR");
            mimeMap.put(".DIR","application/x-director");
            
            mimeKeyList.add(".DCR");
            mimeMap.put(".DIR","application/x-director");
            
            mimeKeyList.add(".DXR");
            mimeMap.put(".DXR","application/x-director");
            
            mimeKeyList.add(".DVI");
            mimeMap.put(".DVI","application/x-dvi");
            
            mimeKeyList.add(".TEX");
            mimeMap.put(".TEX","application/x-tex");
            
            mimeKeyList.add(".LATEX");
            mimeMap.put(".LATEX","application/x-latex");
            
            mimeKeyList.add(".TCL");
            mimeMap.put(".TCL","application/x-tcl");
            
            mimeKeyList.add(".CER");
            mimeMap.put(".CER", "application/x-x509-ca-cert");
            
            mimeKeyList.add(".CRT");
            mimeMap.put(".CRT", "application/x-x509-ca-cert");
            
            mimeKeyList.add(".DER");
            mimeMap.put(".DER", "application/x-x509-ca-cert");
            
            mimeKeyList.add(".MPG");
            mimeMap.put(".MPG", "video/mpeg");
            
            mimeKeyList.add(".MPE");
            mimeMap.put(".MPE", "video/mpeg");
            
            mimeKeyList.add(".MPEG");
            mimeMap.put(".MPEG", "video/mpeg");
            
            mimeKeyList.add(".QT");
            mimeMap.put(".QT", "video/quicktime");
            
            mimeKeyList.add(".MOV");
            mimeMap.put(".MOV", "video/quicktime");
            
            mimeKeyList.add(".AVI");
            mimeMap.put(".AVI", "video/x-msvideo");
            
            mimeKeyList.add(".MOVIE");
            mimeMap.put(".MOVIE", "video/x-sgi-movie");
            
            mimeKeyList.add(".PDB");
            mimeMap.put(".PDB", "chemical/x-pdb");
            
            mimeKeyList.add(".XYZ");
            mimeMap.put(".XYZ", "chemical/x-pdb");
            
            mimeKeyList.add(".ICE");
            mimeMap.put(".ICE", "x-conference/x-cooltalk");
            
            mimeKeyList.add(".JNLP");
            mimeMap.put(".JNLP", "application/x-java-jnlp-file");
            
            mimeKeyList.add(".WRL");
            mimeMap.put(".WRL", "x-world/x-vrml");
            
            mimeKeyList.add(".VRML");
            mimeMap.put(".VRML", "x-world/x-vrml");
            
            mimeKeyList.add(".WML");
            mimeMap.put(".WML", "text/vnd.wap.wml");
            
            mimeKeyList.add(".WMLC");
            mimeMap.put(".WMLC", "application/vnd.wap.wmlc");
            
            mimeKeyList.add(".WMLS");
            mimeMap.put(".WMLS", "text/vnd.wap.wmlscript");
            
            mimeKeyList.add(".WMLSC");
            mimeMap.put(".WMLSC", "application/vnd.wap.wmlscriptc");
            
            mimeKeyList.add(".WBMP");
            mimeMap.put(".WBMP", "image/vnd.wap.wbmp");
        }
        return mimeMap;
    }
    
    
    /**
     * 获取Mime类型
     * @author 刘虻
     * 2008-6-28下午07:44:23
     * @param file 文件路径
     * @return 值
     */
    public String getMimeType(String file) {
        if (file==null) {
            return null;
        }
        String extName;
        int point = file.lastIndexOf(".");
        if(point<0) {
        	return null;
        }
        // 注意：extName前面要有.
        extName = file.substring(point,file.length());
        extName = extName.toUpperCase(); //转换为大写
        
        return getMimeMap().get(extName);
    }
    
    /**
     * 获取默认访问文件序列
     * @author 刘虻
     * 2009-7-22下午03:18:08
     * @return 默认访问文件序列
     */
    public List<String> getWelcomeFileList() {
        if (welcomeFileList==null) {
            welcomeFileList = new ArrayList<String>();
        }
        return welcomeFileList;
    }
    
    /**
     * 处理默认文件配置序列 
     * welcome-file-list
     * @author 刘虻
     * 2009-7-22下午03:13:25
     * @param xml 配置文件对象
     */
    private void fixWelcomeFileList(IViewHandler xml) {
        welcomeFileList = new ArrayList<String>();
        //获取默认文件序列XML信息
        List<IViewHandler> cXmls = 
            xml.getFirstChildNodeByNodeName("welcome-file-list")
                            .getChildNodesByNodeName("welcome-file");
        String fileName; //获取文件元素
        for(IViewHandler cXml:cXmls) {
            fileName = cXml.nt();
            if(fileName.length()<1) {
                continue;
            }
            welcomeFileList.add(fileName);
        }
    }
    
    /**
     * 获取指定会话配置信息值
     * @param key 会话配置信息主键
     * @return    会话配置信息值
     * 2024年7月9日
     * @author MBG
     */
    public String getSessionConfig(String key) {
    	return sessionConfigMap.get(key);
    }
    
    /**
     * 获取指定Cookie配置信息值
     * @param key Cookie配置信息主键
     * @return    Cookie配置信息值
     * 2024年7月9日
     * @author MBG
     */
    public String getCookieConfig(String key) {
    	return cookieConfigMap.get(key);
    }

    /**
     * 获取指定Cookie配置信息值
     * @param key Cookie配置信息主键
     * @return    Cookie配置信息值
     * 2024年7月9日
     * @author MBG
     */
    public boolean getCookieConfigBoolean(String key) {
    	return SBoolean.valueOf(cookieConfigMap.get(key));
    }
    
    /**
     * 解析会话配置信息和Cookie配置信息
     * @param xml  配置信息类
     * 2024年7月9日
     * @author MBG
     */
    private void fixSessionCookieConfig(IViewHandler xml) {
    	sessionConfigMap.clear();
    	cookieConfigMap.clear();
    	// 获取会话信息段中的字节点序列
    	List<IViewHandler> cxmls = 
    			xml.getFirstChildNodeByNodeName("session-config").getChildDealNodes();
        for(IViewHandler cxml:cxmls) {
        	if("cookie-config".equals(cxml.getNodeName())) {
        		// 获取cookie配置信息
        		List<IViewHandler> ccxmls = cxml.getChildDealNodes();
        		for(IViewHandler ccxml:ccxmls) {
        			cookieConfigMap.put(ccxml.getNodeName(),ccxml.getNodeText());
        		}
        	}else {
        		sessionConfigMap.put(cxml.getNodeName(),cxml.getNodeText());
        	}
        }
    }
    
	/**
	 * 获取会话超时时间
	 * @author 刘虻
	 * 2007-9-30下午03:31:58
	 * @return 会话超时时间
	 */
	public int getSessionTimeOut() {
		return sessionTimeOut;
	}
	
	/**
	 * 设置会话超时时间
	 * @param sessionTimeout 会话超时时间（秒）
	 * 2022年9月3日
	 * @author MBG
	 */
	public void setSessionTimeout(int sessionTimeout) {
		this.sessionTimeOut = sessionTimeout;
	}

	/**
	 * 需要设置到配置信息类中的数据容器
	 * @return 需要设置到配置信息类中的数据容器
	 * 2018年11月8日
	 * @author MBG
	 */
	@Override
	public Map<String, String> getPropertyMap() {
		return confDataMap;
	}
	
	/**
	 * 获取web.xml对象
	 * @return
	 * 2024年7月14日
	 * @author MBG
	 */
	public INodeHandler getWebXmlNode() {
		return webXmlNode;
	}
}
